// 衣沾不足惜 2020.7.1
// 事件总线 ,类似vue 事件总线和jquery自定义事件
// 订阅发布者模式
// 额外支持事件漫游
// 一次性绑定多事件 ,
!(function () {
  'use strict'
  var vm = {
    // 事件总线:
    on: function () {},
    emit: function () {},
    off: function () {},
    once: function () {},
    _arrOnEvent: [],
    // 处理先emit后on的情况,将漫游中的emit'暂存'
    _arrCacheEmit: [ {} ]
  }

  /**
     * @description 检测数据类型
     * @param {*} variable
     * @returns {String} type 返回类型,首字母大写
     */
  vm.getType = function (variable) {
    // 11种
    // console.log(Object.prototype.toString.call("sstr"));//[object String]
    // console.log(Object.prototype.toString.call(12));//[object Number]
    // console.log(Object.prototype.toString.call(true));//[object Boolean]
    // console.log(Object.prototype.toString.call(undefined));//[object Undefined]
    // console.log(Object.prototype.toString.call(null));//[object Null]
    // console.log(Object.prototype.toString.call({}));//[object Object]
    // console.log(Object.prototype.toString.call(function () { }));//[object Function]
    // console.log(Object.prototype.toString.call([]));//[object Array]
    // console.log(Object.prototype.toString.call(new Date));//[object Date]
    // console.log(Object.prototype.toString.call(/\d/));//[object RegExp]
    //!! console.log(Object.prototype.toString.call(Symbol));//[object Function] !!
    //console.log(Object.prototype.toString.call(Symbol()));//[object Symbol]
    var type = Object.prototype.toString.call(variable).slice(8, -1)
    return type
  }

  /**
     * @description 根据on与emit的参数执不同的策略
     * @param {String | Array} eventName
     * @param {Function} callback
     */
  vm._eventPublicCheckArgType = function (eventName, callback) {
    let arrEventName = []
    if (Array.isArray(eventName) && eventName.length > 0) {
      //console.log("数组");
      arrEventName = eventName
    } else if (
      typeof eventName == 'string' &&
      eventName.trim().length > 0 &&
      eventName.split(',').length > 1
    ) {
      //console.log("多字符串拆数组");
      arrEventName = eventName.split(',')
    } else if (
      typeof eventName == 'string' &&
      eventName.trim().length > 0 &&
      eventName.split(',').length == 1
    ) {
      //console.log('单字符串还原数组');
      arrEventName = [ eventName ]
    } else {
      console.error('未知类型')
    }
    callback.call(this, arrEventName)
  }

  /**
   * @description 发送事件
   * @param {String | Array} eventName
   * @param {*} params
   * @param {Object} [options={ roaming: false }]
   */
  vm.emit = function (eventName, params, options = { roaming: false }) {
    let sItemEvent = ''
    function funCheckArrFunHaveEventName (arrEventName) {
      var arrEventNameLen = arrEventName.length
      for (let i = 0; i < arrEventNameLen; i++) {
        ;((i) => {
          let isHaveEvent = this._arrOnEvent.some((item, index) => {
            sItemEvent = item
            return item.name == arrEventName[i]
          })
          if (isHaveEvent) {
            sItemEvent.fun(params)
            sItemEvent.options.once ? this.off(sItemEvent.name) : ''
            return true
          } else {
            //   once 不漫游
            if (sItemEvent.options && sItemEvent.options.once) return fasle
            if (options.roaming) {
              console.error(eventName, '该事件未被监听,emit被挂起')
              this._arrCacheEmit.push({ name: eventName, param: params })
            }

            return false
          }
        })(i)
      }
    }
    vm._eventPublicCheckArgType.call(
      this,
      eventName,
      funCheckArrFunHaveEventName
    )
  }

  /**
   * @description 监听事件
   * @param {String | Array} eventName
   * @param {Function} [callback=function () { }]
   */
  vm.on = function (
    eventName,
    callback = function () {},
    options = { once: false }
  ) {
    function funAddon (arrEventName) {
      if (vm.getType(callback) === 'Function') {
        // 先检查存在漫游事件
        this._arrCacheEmit.forEach(function (item, index) {
          for (let i = 0; i < arrEventName.length; i++) {
            // item.name == arrEventName[i].name可能都为undefined....
            if (item.name && arrEventName[i] && item.name == arrEventName[i]) {
              //有漫游
              callback(item.param)
            } else {
              this._arrOnEvent.push({
                name: eventName,
                fun: callback.bind(this),
                options: options
              })
            }
          }
        }, this)
      } else {
        console.error(callback + ' is not function')
      }
    }
    this._eventPublicCheckArgType.call(this, eventName, funAddon)
  }
  /**
   * @description 解除绑定
   * @param {String} eventName
   */
  vm.off = function (eventName) {
    if (!eventName) return
    let index = this._arrOnEvent.findIndex((el) => el.name === eventName)
    index > -1 ? this._arrOnEvent.splice(index, 1) : ''
  }
  vm.once = function (
    eventName,
    callback = function () {},
    options = { once: true }
  ) {
    options.once = true
    vm.on(eventName, callback, options)
  }
  window.vm = vm
  // export
})()
